
package com.hlkj.pay.app.merchant.ext.impl.gtzfpay.handler;
/*
 * Hlpay-Plus aggregate payment system.
 * Copyright (c) 2024-2025 Hlpay Team Copyright has the right of final interpretation.
 */

import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.fasterxml.jackson.core.type.TypeReference;
import com.hlkj.framework.common.pojo.CommonResult;
import com.hlkj.framework.common.util.id.IdUtils;
import com.hlkj.framework.common.util.json.JsonUtils;
import com.hlkj.pay.app.merchant.ext.dto.access.ChannelMerchantAccessContext;
import com.hlkj.pay.app.merchant.ext.dto.access.ChannelMerchantAccessQueryContext;
import com.hlkj.pay.app.merchant.ext.dto.access.ChannelMerchantAccessSignContext;
import com.hlkj.pay.app.merchant.ext.impl.gtzfpay.constant.GtzfPayConstant;
import com.hlkj.pay.app.merchant.ext.impl.gtzfpay.dto.GtzfPayConfig;
import com.hlkj.pay.app.merchant.ext.impl.gtzfpay.dto.req.GtzfAccessRequest;
import com.hlkj.pay.app.merchant.ext.impl.gtzfpay.dto.req.GtzfApplyQueryRequest;
import com.hlkj.pay.app.merchant.ext.impl.gtzfpay.dto.rsp.GtzfApplyQueryRsp;
import com.hlkj.pay.app.merchant.ext.impl.gtzfpay.dto.rsp.GtzfResponse;
import com.hlkj.pay.app.merchant.ext.impl.gtzfpay.utils.GtzfPayRsaUtil;
import com.hlkj.pay.app.merchant.ext.impl.gtzfpay.utils.HttpUtils;
import com.hlkj.pay.dto.merchant.MerchantAccessSignLink;
import com.hlkj.pay.dto.merchant.MerchantElectronicContractDto;
import com.hlkj.pay.enums.MerchantEnum;
import com.hlkj.pay.infrastructure.model.merchant.MerchantAccessCertInfoDO;
import com.hlkj.pay.infrastructure.model.merchant.MerchantAccessInfoDO;
import com.hlkj.pay.infrastructure.model.pay.PayChannelRequestDO;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.ArrayList;
import java.util.Map;

/**
 * @author HlpayTeam
 * @date 2024/10/16 9:10
 */
@Slf4j
@RequiredArgsConstructor
@Service
public class GtzfPayMerchantAccessInfoHandler extends GtzfPayMerchantCommonParamsHandle {

    /**
     * @param channelMerchantAccessContext
     */
    public void merchantAccess(ChannelMerchantAccessContext channelMerchantAccessContext) {
        log.info("国通支付提交进件 请求参数:{}", JsonUtils.toJsonString(channelMerchantAccessContext));
        CommonResult<GtzfPayConfig> gtzfPayConfigCommonResult = channelConfig(channelMerchantAccessContext.getProviderChannelConfig());
        // 配置转换
        if (!gtzfPayConfigCommonResult.isSuccess()) {
            channelMerchantAccessContext.setRemark(gtzfPayConfigCommonResult.getMsg());
            channelMerchantAccessContext.setProcessStatus(Boolean.FALSE);
            return;
        }
        GtzfPayConfig gtzfPayConfig = gtzfPayConfigCommonResult.getData();
        // 1. 数据初始化
        PayChannelRequestDO payChannelRequestDO = new PayChannelRequestDO();
        channelMerchantAccessContext.setPayChannelRequestDO(payChannelRequestDO);
        try {
            // 参数组装
            // 新增参数转换
            String requestId = IdUtils.getSnowflake().nextIdStr();
            channelMerchantAccessContext.getMerchantAccessDto().getMerchantAccessInfo().setRequestId(requestId);
            CommonResult<GtzfAccessRequest> paramsCommonResult = GtzfPayMerchantParamsHandle.merchantApplyParams(channelMerchantAccessContext, gtzfPayConfig);
            if (!paramsCommonResult.isSuccess()) {
                channelMerchantAccessContext.setProcessStatus(Boolean.FALSE);
                channelMerchantAccessContext.setAccessStatus(MerchantEnum.ACCESS_STATUS.APPROVE_REFUSE);
                channelMerchantAccessContext.setRemark(paramsCommonResult.getMsg());
                log.error("国通支付开户参数校验失败 message: {}", paramsCommonResult.getMsg());
                return;
            }
            GtzfAccessRequest params = paramsCommonResult.getData();

            fillBankCode(params, gtzfPayConfig, channelMerchantAccessContext);

            // 记录请求参数
            payChannelRequestDO.setRequestId(requestId);
            String url = domain(channelMerchantAccessContext.isTest());

            if (!StringUtils.hasText(params.getBusType())) {
                url += GtzfPayConstant.MERCHANT_MINI_ADD;
            } else {
                url += GtzfPayConstant.MERCHANT_ADD;
            }

            String sign = GtzfPayRsaUtil.encrypt(JSONUtil.parseObj(params), gtzfPayConfig.getMchPublicKey());
            params.setSign(sign);

            payChannelRequestDO.setRequestTime(System.currentTimeMillis());
            payChannelRequestDO.setRequestParams(JsonUtils.toJsonString(params));
            log.info("国通支付新增进件请求参数:{}", JsonUtils.toJsonString(params));
            String response = HttpUtils.post(url, JSONUtil.parseObj(params));
            log.info("国通支付新增进件返回参数:{}", response);
            payChannelRequestDO.setResponse(response);
            JSONObject obj = JsonUtils.parseObj(response);
            GtzfPayMerchantParamsHandle.merchantApplyParamsParse(obj, channelMerchantAccessContext, params);
        } catch (Exception e) {
            e.printStackTrace();
            log.error("国通支付开户请求失败,失败信息 message: {}", e.getMessage());
            channelMerchantAccessContext.setRemark("国通支付开户请求失败,失败信息" + (StringUtils.hasText(e.getMessage()) ? e.getMessage() : " 数据解析异常"));
            channelMerchantAccessContext.setProcessStatus(Boolean.FALSE);
            channelMerchantAccessContext.setAccessStatus(MerchantEnum.ACCESS_STATUS.APPROVE_REFUSE);
        }
    }

    public void fillBankCode(GtzfAccessRequest request, GtzfPayConfig config, ChannelMerchantAccessContext channelMerchantAccessContext) throws Exception {
        CommonResult<Map<String, String>> bankPa = GtzfPayMerchantParamsHandle.queryInfoByCard(request.getBankno(), config);
        Map<String, String> params = bankPa.getData();
        String sign = GtzfPayRsaUtil.encrypt(JSONUtil.parseObj(params), config.getMchPublicKey());
        params.put("sign", sign);

        String url = domain(channelMerchantAccessContext.isTest()) + GtzfPayConstant.MERCHANT_QUERY_CARD;
        log.info("国通支付获取银行信息请求参数:{}", JsonUtils.toJsonString(params));
        String response = HttpUtils.get(url, JSONUtil.parseObj(params));
        log.info("国通支付获取银行信息返回参数:{}", response);
        JSONObject rsp = JSONUtil.parseObj(response);
        if (!"000000".equals(rsp.getStr("code"))) {
            log.error("国通支付获取银行信息失败 失败信息: {}", rsp.getStr("msg"));
            throw new Exception("国通支付获取银行信息失败 失败信息: " + rsp.getStr("msg"));
        }
        JSONArray dataArr = rsp.getJSONArray("data");
        request.setBankCode(dataArr.getJSONObject(0).getStr("bankCode"));
    }

    /**
     * 进件查询
     *
     * @param channelMerchantAccessQueryContext
     */
    public void accessQueryRequest(ChannelMerchantAccessQueryContext channelMerchantAccessQueryContext) {
        CommonResult<GtzfPayConfig> gtzfPayConfigCommonResult = channelConfig(channelMerchantAccessQueryContext.getProviderChannelConfig());
        // 配置转换
        if (!gtzfPayConfigCommonResult.isSuccess()) {
            channelMerchantAccessQueryContext.setProcessStatus(Boolean.FALSE);
            channelMerchantAccessQueryContext.setRemark(gtzfPayConfigCommonResult.getMsg());
            return;
        }
        GtzfPayConfig gtzfPayConfig = gtzfPayConfigCommonResult.getData();
        try {
            CommonResult<GtzfApplyQueryRequest> paramsCommonResult  = GtzfPayMerchantParamsHandle.queryApplyStatus(channelMerchantAccessQueryContext.getMerchantAccessInfo().getSubMchId(), gtzfPayConfig);
            GtzfApplyQueryRequest params = paramsCommonResult.getData();
            String sign = GtzfPayRsaUtil.encrypt(JSONUtil.parseObj(params), gtzfPayConfig.getMchPublicKey());
            params.setSign(sign);
            String url = domain(channelMerchantAccessQueryContext.isTest()) + GtzfPayConstant.MERCHANT_APPLY_QUERY;
            log.info("国通支付进件查询请求参数:{}", JsonUtils.toJsonString(params));
            String response = HttpUtils.get(url, JSONUtil.parseObj(params));
            log.info("国通支付进件查询返回参数:{}", response);
            GtzfResponse<GtzfApplyQueryRsp> rsp = JsonUtils.parseObject(response, new TypeReference<GtzfResponse<GtzfApplyQueryRsp>>() {
            });
            if (!"000000".equals(rsp.getCode())) {
                channelMerchantAccessQueryContext.setRemark(rsp.getMsg());
                log.error("国通支付进件查询异常 message: {}", rsp.getMsg());
                channelMerchantAccessQueryContext.setProcessStatus(Boolean.FALSE);
                channelMerchantAccessQueryContext.setAccessStatus(MerchantEnum.ACCESS_STATUS.CHANNEL_APPROVE);
                channelMerchantAccessQueryContext.setRemark(rsp.getMsg());
                return;
            }
            GtzfApplyQueryRsp queryRsp = rsp.getData();
            //0暂存、1审核中、2审核通过、3审核不通过
             switch (queryRsp.getUsrStatus()) {
                case "2":
                    //成功
                    channelMerchantAccessQueryContext.setAccessStatus(MerchantEnum.ACCESS_STATUS.WAIT_SIGN);
                    break;
                case "3":
                    //失败
                    channelMerchantAccessQueryContext.setProcessStatus(Boolean.FALSE);
                    channelMerchantAccessQueryContext.setAccessStatus(MerchantEnum.ACCESS_STATUS.APPROVE_REFUSE);
                    break;
            }
            if (StringUtils.hasText(queryRsp.getAuthResult()))
                channelMerchantAccessQueryContext.setRemark(queryRsp.getAuthResult());
        } catch (Exception e) {
            e.printStackTrace();
            log.error("国通支付进件查询请求失败,失败信息 message: {}", e.getMessage());
            channelMerchantAccessQueryContext.setRemark("国通支付进件查询请求失败,失败信息" + e.getMessage());
            channelMerchantAccessQueryContext.setProcessStatus(Boolean.FALSE);
            channelMerchantAccessQueryContext.setAccessStatus(MerchantEnum.ACCESS_STATUS.CHANNEL_APPROVE);
        }
    }

    public void previewContract(ChannelMerchantAccessSignContext channelMerchantAccessSignContext) {
        CommonResult<GtzfPayConfig> gtzfPayConfigCommonResult = channelConfig(channelMerchantAccessSignContext.getProviderChannelConfig());
        // 配置转换
        if (!gtzfPayConfigCommonResult.isSuccess()) {
            channelMerchantAccessSignContext.setProcessStatus(Boolean.FALSE);
            channelMerchantAccessSignContext.setRemark(gtzfPayConfigCommonResult.getMsg());
            return;
        }
        GtzfPayConfig gtzfPayConfig = gtzfPayConfigCommonResult.getData();
        try {
            MerchantAccessInfoDO merchantAccessInfoDO = channelMerchantAccessSignContext.getMerchantAccessInfoDO();

            CommonResult<Map<String, String>> paramsCommonResult = GtzfPayMerchantParamsHandle.previewContract(merchantAccessInfoDO.getSubMchId(), gtzfPayConfig);
            Map<String, String> params = paramsCommonResult.getData();
            String sign = GtzfPayRsaUtil.encrypt(JSONUtil.parseObj(params), gtzfPayConfig.getMchPublicKey());
            params.put("sign", sign);

            String url = domain(channelMerchantAccessSignContext.isTest()) + GtzfPayConstant.ELECTRONIC_SEND_SMS;
            log.info("国通支付获取安心签合同请求参数:{}", JsonUtils.toJsonString(params));
            String response = HttpUtils.post(url, JSONUtil.parseObj(params));
            log.info("国通支付获取安心签合同返回参数:{}", response);
            JSONObject rsp = JSONUtil.parseObj(response);
            if (!"000000".equals(rsp.getStr("code"))) {
                channelMerchantAccessSignContext.setRemark(rsp.getStr("msg"));
                log.error("国通支付获取安心签合同异常 message: {}", rsp.getStr("msg"));
                channelMerchantAccessSignContext.setProcessStatus(Boolean.FALSE);
                channelMerchantAccessSignContext.setAccessStatus(MerchantEnum.ACCESS_STATUS.APPROVE_REFUSE);
                channelMerchantAccessSignContext.setRemark(rsp.getStr("msg"));
            }
            JSONObject dataObj = rsp.getJSONObject("data");

            MerchantAccessInfoDO merchantAccessInfo = channelMerchantAccessSignContext.getMerchantAccessInfoDO();
            merchantAccessInfo.setStatus(MerchantEnum.ACCESS_STATUS.WAIT_SIGNING.getCode());
            channelMerchantAccessSignContext.setAccessStatus(MerchantEnum.ACCESS_STATUS.WAIT_SIGNING);
            MerchantAccessSignLink merchantAccessSignLink = new MerchantAccessSignLink();
            channelMerchantAccessSignContext.setAuditStatus(MerchantEnum.CHANNEL_CONFIG_STATUS.SIGN);
            merchantAccessSignLink.setLink(dataObj.getStr("filePath"));
            merchantAccessSignLink.setName("国通支付电子协议");
            channelMerchantAccessSignContext.setSignLinks(new ArrayList<>() {
                {
                    add(merchantAccessSignLink);
                }
            });
        } catch (Exception e) {
            e.printStackTrace();
            log.error("国通支付获取安心签合同请求失败,失败信息 message: {}", e.getMessage());
            channelMerchantAccessSignContext.setRemark("国通支付获取安心签合同请求失败,失败信息" + e.getMessage());
            channelMerchantAccessSignContext.setProcessStatus(Boolean.FALSE);
        }
    }

    public void getSignH5Url(ChannelMerchantAccessSignContext channelMerchantAccessSignContext) {
        CommonResult<GtzfPayConfig> gtzfPayConfigCommonResult = channelConfig(channelMerchantAccessSignContext.getProviderChannelConfig());
        // 配置转换
        if (!gtzfPayConfigCommonResult.isSuccess()) {
            channelMerchantAccessSignContext.setProcessStatus(Boolean.FALSE);
            channelMerchantAccessSignContext.setRemark(gtzfPayConfigCommonResult.getMsg());
            return;
        }
        GtzfPayConfig gtzfPayConfig = gtzfPayConfigCommonResult.getData();
        try {
            MerchantAccessInfoDO merchantAccessInfoDO = channelMerchantAccessSignContext.getMerchantAccessInfoDO();
            CommonResult<Map<String, String>> paramsCommonResult = GtzfPayMerchantParamsHandle.getSignH5Url(merchantAccessInfoDO.getSubMchId(), gtzfPayConfig);
            Map<String, String> params = paramsCommonResult.getData();
            String sign = GtzfPayRsaUtil.encrypt(JSONUtil.parseObj(params), gtzfPayConfig.getMchPublicKey());
            params.put("sign", sign);

            String url = domain(channelMerchantAccessSignContext.isTest()) + GtzfPayConstant.ELECTRONIC_CONTRACT_H5;
            log.info("国通支付获取安心签H5链接请求参数:{}", JsonUtils.toJsonString(params));
            String response = HttpUtils.post(url, JSONUtil.parseObj(params));
            log.info("国通支付获取安心签H5链接返回参数:{}", response);
            JSONObject rsp = JSONUtil.parseObj(response);
            //020004 已签约
            if (!"000000".equals(rsp.getStr("code")) && !"020004".equals(rsp.getStr("code"))) {//
                channelMerchantAccessSignContext.setRemark(rsp.getStr("msg"));
                log.error("国通支付获取安心签H5链接异常 message: {}", rsp.getStr("msg"));
                channelMerchantAccessSignContext.setProcessStatus(Boolean.FALSE);
                channelMerchantAccessSignContext.setAccessStatus(MerchantEnum.ACCESS_STATUS.APPROVE_REFUSE);
                channelMerchantAccessSignContext.setRemark(rsp.getStr("msg"));
            }

            MerchantAccessInfoDO merchantAccessInfo = channelMerchantAccessSignContext.getMerchantAccessInfoDO();
            merchantAccessInfo.setStatus(MerchantEnum.ACCESS_STATUS.WAIT_SET.getCode());
            channelMerchantAccessSignContext.setAccessStatus(MerchantEnum.ACCESS_STATUS.WAIT_SET);
            MerchantAccessSignLink merchantAccessSignLink = new MerchantAccessSignLink();
            channelMerchantAccessSignContext.setAuditStatus(MerchantEnum.CHANNEL_CONFIG_STATUS.SUBMERINFO);
            if ("000000".equals(rsp.getStr("code"))) {
                JSONObject dataObj = rsp.getJSONObject("data");
                merchantAccessSignLink.setLink(dataObj.getStr("signH5Url"));
                merchantAccessSignLink.setName("国通支付安心签协议");
                channelMerchantAccessSignContext.setSignLinks(new ArrayList<>() {
                    {
                        add(merchantAccessSignLink);
                    }
                });
            }
        } catch (Exception e) {
            e.printStackTrace();
            log.error("国通支付获取安心签H5链接请求失败,失败信息 message: {}", e.getMessage());
            channelMerchantAccessSignContext.setRemark("国通支付获取安心签H5链接请求失败,失败信息" + e.getMessage());
            channelMerchantAccessSignContext.setProcessStatus(Boolean.FALSE);
        }
    }

    public void sendAxqCode(ChannelMerchantAccessSignContext channelMerchantAccessSignContext) {
        CommonResult<GtzfPayConfig> gtzfPayConfigCommonResult = channelConfig(channelMerchantAccessSignContext.getProviderChannelConfig());
        // 配置转换
        if (!gtzfPayConfigCommonResult.isSuccess()) {
            channelMerchantAccessSignContext.setProcessStatus(Boolean.FALSE);
            channelMerchantAccessSignContext.setRemark(gtzfPayConfigCommonResult.getMsg());
            return;
        }
        GtzfPayConfig gtzfPayConfig = gtzfPayConfigCommonResult.getData();
        try {
            MerchantAccessInfoDO merchantAccessInfoDO = channelMerchantAccessSignContext.getMerchantAccessInfoDO();
            MerchantAccessCertInfoDO merchantAccessLegal = channelMerchantAccessSignContext.getMerchantAccessLegal();

            CommonResult<Map<String, String>> paramsCommonResult = GtzfPayMerchantParamsHandle.sendAxqCode(merchantAccessInfoDO.getSubMchId(), merchantAccessLegal.getPhone(), merchantAccessLegal.getCertNo(), gtzfPayConfig);
            Map<String, String> params = paramsCommonResult.getData();
            String sign = GtzfPayRsaUtil.encrypt(JSONUtil.parseObj(params), gtzfPayConfig.getMchPublicKey());
            params.put("sign", sign);

            String url = domain(channelMerchantAccessSignContext.isTest()) + GtzfPayConstant.ELECTRONIC_SEND_SMS;
            log.info("国通支付安心签验证码请求参数:{}", JsonUtils.toJsonString(params));
            String response = HttpUtils.post(url, JSONUtil.parseObj(params));
            log.info("国通支付安心签验证码返回参数:{}", response);
            JSONObject rsp = JSONUtil.parseObj(response);
            if (!"000000".equals(rsp.getStr("code"))) {
                channelMerchantAccessSignContext.setRemark(rsp.getStr("msg"));
                log.error("国通支付安心签验证码异常 message: {}", rsp.getStr("msg"));
                channelMerchantAccessSignContext.setProcessStatus(Boolean.FALSE);
                channelMerchantAccessSignContext.setAccessStatus(MerchantEnum.ACCESS_STATUS.APPROVE_REFUSE);
                channelMerchantAccessSignContext.setRemark(rsp.getStr("msg"));
            }
        } catch (Exception e) {
            e.printStackTrace();
            log.error("国通支付安心签验证码请求失败,失败信息 message: {}", e.getMessage());
            channelMerchantAccessSignContext.setRemark("国通支付安心签验证码请求失败,失败信息" + e.getMessage());
            channelMerchantAccessSignContext.setProcessStatus(Boolean.FALSE);
        }
    }

    public void supplementary(ChannelMerchantAccessSignContext channelMerchantAccessSignContext) {
        CommonResult<GtzfPayConfig> gtzfPayConfigCommonResult = channelConfig(channelMerchantAccessSignContext.getProviderChannelConfig());
        // 配置转换
        if (!gtzfPayConfigCommonResult.isSuccess()) {
            channelMerchantAccessSignContext.setProcessStatus(Boolean.FALSE);
            channelMerchantAccessSignContext.setRemark(gtzfPayConfigCommonResult.getMsg());
            return;
        }
        GtzfPayConfig gtzfPayConfig = gtzfPayConfigCommonResult.getData();
        try {
            MerchantAccessInfoDO merchantAccessInfoDO = channelMerchantAccessSignContext.getMerchantAccessInfoDO();
            MerchantElectronicContractDto merchantElectronicContractDto = channelMerchantAccessSignContext.getMerchantElectronicContractDto();

            CommonResult<Map<String, String>> paramsCommonResult = GtzfPayMerchantParamsHandle.supplementary(merchantElectronicContractDto.getCheckCode(), merchantAccessInfoDO.getSubMchId(), gtzfPayConfig);
            Map<String, String> params = paramsCommonResult.getData();
            String sign = GtzfPayRsaUtil.encrypt(JSONUtil.parseObj(params), gtzfPayConfig.getMchPublicKey());
            params.put("sign", sign);

            String url = domain(channelMerchantAccessSignContext.isTest()) + GtzfPayConstant.ELECTRONIC_SEND_SMS;
            log.info("国通支付安心签补签请求参数:{}", JsonUtils.toJsonString(params));
            String response = HttpUtils.post(url, JSONUtil.parseObj(params));
            log.info("国通支付安心签补签返回参数:{}", response);
            JSONObject rsp = JSONUtil.parseObj(response);
            if (!"000000".equals(rsp.getStr("code"))) {
                channelMerchantAccessSignContext.setRemark(rsp.getStr("msg"));
                log.error("国通支付安心签补签异常 message: {}", rsp.getStr("msg"));
                channelMerchantAccessSignContext.setProcessStatus(Boolean.FALSE);
                channelMerchantAccessSignContext.setAccessStatus(MerchantEnum.ACCESS_STATUS.APPROVE_REFUSE);
                channelMerchantAccessSignContext.setRemark(rsp.getStr("msg"));
            }
            channelMerchantAccessSignContext.setAccessStatus(MerchantEnum.ACCESS_STATUS.WAIT_SET);
            channelMerchantAccessSignContext.setAuditStatus(MerchantEnum.CHANNEL_CONFIG_STATUS.SUBMERINFO);
        } catch (Exception e) {
            e.printStackTrace();
            log.error("国通支付安心签补签请求失败,失败信息 message: {}", e.getMessage());
            channelMerchantAccessSignContext.setRemark("国通支付安心签补签请求失败,失败信息" + e.getMessage());
            channelMerchantAccessSignContext.setProcessStatus(Boolean.FALSE);
        }
    }
}
